#include <cassert>
#include <cstdint>
#include <random>
#include <systemc.h>

template<uint32_t W>
SC_MODULE(SequenceDetector) {
    sc_in<bool>             clock;
    sc_in<bool>             reset;
    sc_in<bool>             input;
    sc_out<bool>            output;

    sc_uint<W>              target;
    sc_signal<sc_uint<W>>   current;

    void shift_logic() {
        if (reset.read()) {
            current.write(0);
        } else { // 触发时钟上升沿时移位
            current.write((current.read() << 1) | input.read());
        }
    }

    void output_logic() {
        output.write(current == target);
    }
    
    SC_HAS_PROCESS(SequenceDetector);

    SequenceDetector(sc_module_name name, sc_uint<W> target = 0) 
    : sc_module(name) {
        this->target = target;
        SC_METHOD(shift_logic);
        sensitive << clock.pos() << reset;
        dont_initialize(); // 不初始化，避免在仿真开始时触发

        SC_METHOD(output_logic);
        sensitive << current << reset;
    }
};

int sc_main(int argc, char **argv) {
    const uint32_t W = 6;
    const uint32_t period = 4;
    
    sc_clock clock("clock", period, SC_NS);
    sc_signal<bool> reset;
    sc_signal<bool> input;
    sc_signal<bool> output;

    SequenceDetector<W> detector("sequence_detector", 0b101011);
    detector.clock(clock);
    detector.reset(reset);
    detector.input(input);
    detector.output(output);

    // 随机数生成
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(0, 1);

    // [波形追踪]
    sc_trace_file *tf = sc_create_vcd_trace_file("detector");
    tf->set_time_unit(1, SC_NS); // 设置时间单位为 1 ns
    sc_trace(tf, clock, "clock");
    sc_trace(tf, reset, "reset");
    sc_trace(tf, input, "input");
    sc_trace(tf, output, "output");
    sc_trace(tf, detector.target, "target");
    sc_trace(tf, detector.current, "current");

    int i = 0;
    // [施加激励]
    reset.write(true);
    while (i <= 600) {
        if (i == 13) {
            reset.write(false);
        }
        if (i % 4 == 3) {
            input.write(dis(gen));
        }
        sc_start(1, SC_NS);
        i++;
    }

    sc_close_vcd_trace_file(tf);

    return 0;
}
